//
// Created by ta&to on 2022/9/28.
//
#include "http_multi_io.h"
#if defined(SOCKET_SERVER_POLL) && !defined(PLATFORM_WINDOWS)
static inline void _init_poll(struct event_container_s *ev_container) {
    initPipe(ev_container->pipefd);
    ev_container->current_read_link = 0;
    ev_container->current_write_link = 0;
    ev_container->poll_ev_fds = (struct pollfd*) http_calloc(ev_container->max_link * sizeof(struct pollfd));
    ev_container->event_read_fds = (struct event_fds_s*) http_calloc(ev_container->max_link * sizeof(struct event_fds_s));
    ev_container->event_write_fds = (struct event_fds_s*) http_calloc(ev_container->max_link * sizeof(struct event_fds_s));
}
// 初始化fds结构体数组
static inline void _create_poll(struct event_container_s *ev_container)
{
    for (int i = 0; i < ev_container->max_link;
    ev_container->poll_ev_fds[i].fd = -1, ev_container->poll_ev_fds[i].events = 0, ev_container->poll_ev_fds[i].revents = 0,
    ev_container->event_read_fds[i].fd = -1, ev_container->event_read_fds[i].events = 0,
    ev_container->event_write_fds[i].fd = -1, ev_container->event_write_fds[i].events = 0,++i);
    add_event(ev_container, ev_container->pipefd[0], IO_ADD_RD_EVENT, pipe_read_fd_handler, NULL, -1);
}

// 向fds结构体数组中插入一个文件描述符
static inline int _add_event(struct event_container_s *ev_container, int fd, uint32_t event, fd_callback_handler_func fd_handler, void* args, int n)//此处flag是为了判断是文件描述符c，还是listenfd，来设置events
{
    if(!(event & IO_ADD_RD_EVENT ^ IO_ADD_RD_EVENT)){
        if(ev_container->current_read_link < ev_container->max_link) {
            for(int i = 0; i < ev_container->max_link; ++i)
            {
                if (ev_container->event_read_fds[i].fd == -1){
                    ev_container->event_read_fds[i].fd = fd;
                    ev_container->event_read_fds[i].events = IO_ADD_RD_EVENT;
                    ev_container->event_read_fds[i].fd_handler = fd_handler;
                    ev_container->event_read_fds[i].args = args;
                    ev_container->event_read_fds[i].invoke_num = n;
                    atomicIncr(ev_container->current_read_link, 1);
                    break;
                }
            }
        }else{
            error(ev_container->logs, "max connections arrive, maxconn is %d current accept fd is %d exit\n", ev_container->current_read_link, fd);
            putData(ev_container->logs, fd,"bye",4);
            CloseAll(ev_container->logs, 0, fd);
            return -1;
        }
    }
    if(!(event & IO_ADD_WT_EVENT ^ IO_ADD_WT_EVENT)){
        if(ev_container->current_write_link < ev_container->max_link) {
            for(int i = 0; i < ev_container->max_link; ++i)
            {
                if (ev_container->event_write_fds[i].fd == -1){
                    ev_container->event_write_fds[i].fd = fd;
                    ev_container->event_write_fds[i].events = IO_ADD_WT_EVENT;
                    ev_container->event_write_fds[i].fd_handler = fd_handler;
                    ev_container->event_write_fds[i].args = args;
                    ev_container->event_write_fds[i].invoke_num = n;
                    atomicIncr(ev_container->current_write_link, 1);
                    break;
                }
            }
        }else{
            error(ev_container->logs, "max connections arrive, maxconn is %d current accept fd is %d exit\n", ev_container->current_read_link, fd);
            putData(ev_container->logs, fd,"bye",4);
            CloseAll(ev_container->logs, 0, fd);
            return -1;
        }
    }
    return 0;
}

// 从fds结构体数组中删除一个文件描述符
static inline int _del_event(struct event_container_s *ev_container, int fd, uint32_t event) {
    for(int i = 0; i < ev_container->max_link; ++i)
    {
        if(ev_container->event_read_fds[i].fd == fd && !(event & IO_ADD_RD_EVENT ^ IO_ADD_RD_EVENT))
        {
            ev_container->event_read_fds[i].fd = -1;
            ev_container->event_read_fds[i].events = 0;
            atomicDecr(ev_container->current_read_link, 1);
        }
        if(ev_container->event_write_fds[i].fd == fd && !(event & IO_ADD_WT_EVENT ^ IO_ADD_WT_EVENT))
        {
            ev_container->event_write_fds[i].fd = -1;
            ev_container->event_write_fds[i].events = 0;
            atomicDecr(ev_container->current_write_link, 1);
        }
        if(ev_container->poll_ev_fds[i].fd == fd)
        {
            int fds = -1;
            uint32_t events = 0;
            uint32_t revents = 0;
            if (ev_container->event_read_fds[i].fd == fd ) {
                fds = fd;
                revents |= ev_container->poll_ev_fds[i].revents;
                events |= ev_container->event_read_fds[i].events;
            }
            if (ev_container->event_write_fds[i].fd == fd ) {
                fds = fd;
                revents |= ev_container->poll_ev_fds[i].revents;
                events |= ev_container->event_write_fds[i].events;
            }
            ev_container->poll_ev_fds[i].fd = fds;
            ev_container->poll_ev_fds[i].events = events;
            ev_container->poll_ev_fds[i].revents = revents;
        }
    }
    return fd;
}

static inline void _reload_poll(struct event_container_s *ev_container) {
    for (int i = 0; i < ev_container->max_link;
         ev_container->poll_ev_fds[i].fd = -1, ev_container->poll_ev_fds[i].events = 0, ev_container->poll_ev_fds[i].revents = 0, ++i);
    for(int i = 0; i < ev_container->max_link; i++) {
        if (ev_container->event_read_fds[i].fd != -1) {
            ev_container->poll_ev_fds[i].fd = ev_container->event_read_fds[i].fd;
            ev_container->poll_ev_fds[i].events |= ev_container->event_read_fds[i].events;
            ev_container->poll_ev_fds[i].revents |= POLLRDNEW;
        }
        if (ev_container->event_write_fds[i].fd != -1) {
            ev_container->poll_ev_fds[i].fd = ev_container->event_write_fds[i].fd;
            ev_container->poll_ev_fds[i].events |= ev_container->event_write_fds[i].events;
            ev_container->poll_ev_fds[i].revents |= POLLWTNEW;
        }
    }
}

static inline void _poll_loop(struct event_container_s *ev_container) {
    while(1)
    {
        if(ev_container->status == 1) {
            free_event_io(ev_container);
            closePipe(ev_container->pipefd[0]);
            closePipe(ev_container->pipefd[1]);
            return;
        }
        _reload_poll(ev_container);
        if(poll(ev_container->poll_ev_fds, ev_container->max_link,
                              (ISNOTNULL(ev_container->tvp) ? (ev_container->tvp->tv_sec * 1000 + (ev_container->tvp->tv_usec + 999) / 1000) : -1)) <= 0)  // 设置poll
        {
            error(ev_container->logs, "poll error\n");
            continue;
        }
        event_p_t e_args;
        for(int i = 0; i < ev_container->max_link; ++i) {
            if (ev_container->poll_ev_fds[i].fd == -1)
                continue;
            if (ev_container->event_read_fds[i].fd != -1 && ev_container->poll_ev_fds[i].revents & IO_ADD_RD_EVENT) {
                if(ev_container->event_read_fds[i].invoke_num > 0){
                    ev_container->event_read_fds[i].invoke_num--;
                }
                e_args.fd = ev_container->event_read_fds[i].fd;
                e_args.args = ev_container->event_read_fds[i].args;   fd_callback_handler_func fd_handler = ev_container->event_read_fds[i].fd_handler;
                if(ev_container->event_read_fds[i].invoke_num == 0){
                    _del_event(ev_container,ev_container->event_read_fds[i].fd, IO_ADD_RD_EVENT);
                }
                fd_handler(ev_container, &e_args);
            }
            if (ev_container->event_write_fds[i].fd != -1 && ev_container->poll_ev_fds[i].revents & IO_ADD_WT_EVENT) {
                if(ev_container->event_write_fds[i].invoke_num > 0){
                    ev_container->event_write_fds[i].invoke_num--;
                }
                e_args.fd = ev_container->event_write_fds[i].fd;
                e_args.args = ev_container->event_write_fds[i].args;
                fd_callback_handler_func fd_handler = ev_container->event_write_fds[i].fd_handler;
                if(ev_container->event_write_fds[i].invoke_num == 0){
                    _del_event(ev_container,ev_container->event_write_fds[i].fd, IO_ADD_WT_EVENT);
                }
                fd_handler(ev_container, &e_args);
            }
        }
    }
}

void _free_poll(struct event_container_s *ev_container) {
    if(ev_container->poll_ev_fds) {
        http_free(ev_container->poll_ev_fds);
    }
    if(ev_container->event_read_fds) {
        http_free(ev_container->event_read_fds);
    }
    if(ev_container->event_write_fds) {
        http_free(ev_container->event_write_fds);
    }
}

static inline void _triggerIo(struct event_container_s *ev_container){
    write(ev_container->pipefd[1], "", 1);
}

void init_event_io(struct event_container_s *ev_container) {
    _init_poll(ev_container);
}

void create_event_io(struct event_container_s *ev_container) {
    _create_poll(ev_container);
}

int add_event(struct event_container_s *ev_container, int fd, uint32_t event, fd_callback_handler_func fd_handler, void *args, int n) {
    _add_event(ev_container, fd, event, fd_handler, args, n);
}

int del_event(struct event_container_s *ev_container, int fd, uint32_t event) {
    return _del_event(ev_container, fd, event);
}

int io_cycle(struct event_container_s *ev_container){
    _poll_loop(ev_container);
}
void triggerIo(struct event_container_s *ev_container) {
    _triggerIo(ev_container);
}
void free_event_io(struct event_container_s *ev_container) {
    _free_poll(ev_container);
}
#endif
